package cn.catsdad.service.impl;

import cn.catsdad.base.page.PageBean;
import cn.catsdad.base.page.PageParam;
import cn.catsdad.base.service.impl.BaseCrudServiceImpl;
import cn.catsdad.dto.DocumentDTO;
import cn.catsdad.exception.BaseException;
import cn.catsdad.repository.DocumentRepository;
import cn.catsdad.service.api.DocumentService;
import cn.catsdad.util.EnvironmentUtil;
import cn.catsdad.util.StringUtil;
import cn.catsdad.vo.UploadVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 附件service实现
 *
 * @author xuyonglong
 * @version V1.0 2023/4/25
 */
@Slf4j
@Service
public class DocumentServiceImpl extends BaseCrudServiceImpl<DocumentDTO, Long, DocumentRepository> implements DocumentService {

    @Override
    public void pageQuery(PageBean<DocumentDTO> page, PageParam param) {
        page.setEntityName("DtoDocument d").setQuery("select d");
        super.pageQuery(page, param);
    }

    @Override
    public Map<Long, List<DocumentDTO>> queryByObjectIds(Collection<Long> objectIds, String objectKey) {
        Map<Long, List<DocumentDTO>> result = new HashMap<>(objectIds.size());
        if (StringUtil.isNotEmpty(objectIds)) {
            result = repository.findByObjectIdInAndObjectKeyAndIsDeletedFalse(objectIds, objectKey)
                    .stream().collect(Collectors.groupingBy(DocumentDTO::getObjectId));
        }
        return result;
    }

    @Override
    @Transactional
    public List<DocumentDTO> uploadFiles(UploadVo uploadVo) {
        List<MultipartFile> files = uploadVo.getFiles();
        List<DocumentDTO> saveList = new ArrayList<>();
        for (MultipartFile file : files) {
            DocumentDTO document = new DocumentDTO();
            document.setObjectId(uploadVo.getObjectId());
            document.setObjectKey(uploadVo.getObjectKey());
            document.setFileName(file.getOriginalFilename());
            String[] fileName = Objects.requireNonNull(file.getOriginalFilename()).split("\\.");
            if (fileName.length > 0) {
                document.setSuffix(fileName[fileName.length - 1]);
            }
            document.setSize(file.getSize());
            document.setDownloadCount(0);
            document.setFolder(uploadVo.getObjectKey() + File.separator + uploadVo.getObjectId());
            document.setPhysicalPath(getUploadPath() + File.separator + document.getFolder() + File.separator + document.getFileName());
            saveList.add(document);
            try {
                File saveFile = new File(document.getPhysicalPath());
                mkdirs(document);
                file.transferTo(saveFile);
            } catch (IOException e) {
                throw new BaseException("文件上传失败，错误信息：" + e.getMessage());
            }
        }
        if (StringUtil.isNotEmpty(saveList)) {
            saveAll(saveList);
        }
        return saveList;
    }

    private String getUploadPath() {
        return EnvironmentUtil.getProperty(new EnvironmentUtil.PropertyParam<String>().setKey("app.file.uploadPath").setDefaultValue("/"));
    }

    private void mkdirs(DocumentDTO document) {
        String physicalPath = document.getPhysicalPath();
        physicalPath = physicalPath.replace(File.separator + document.getFileName(), "");
        if (StringUtil.isNotEmpty(physicalPath)) {
            File path = new File(physicalPath);
            path.mkdirs();
        }
    }

    @Override
    @Transactional
    public void downloadFile(Long documentId, HttpServletResponse response) {
        DocumentDTO document = queryById(documentId);
        downloadFile(document.getPhysicalPath(), response);
        document.setDownloadCount(document.getDownloadCount() + 1);
        update(document);
    }

    /**
     * 文件下载
     *
     * @param path     文件绝对路径
     * @param response 响应流
     */
    public void downloadFile(String path, HttpServletResponse response) {
        if (StringUtil.isNotEmpty(path)) {
            InputStream inputStream = null;
            try {
                inputStream = Files.newInputStream(Paths.get(path));
                response.reset();
                response.setContentType("application/octet-stream");
                String filename = new File(path).getName();
                response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
                ServletOutputStream outputStream = response.getOutputStream();
                byte[] b = new byte[1024];
                int len;
                while ((len = inputStream.read(b)) > 0) {
                    outputStream.write(b, 0, len);
                }
            } catch (Exception e) {
                throw new BaseException("文件下载失败，错误信息：" + e.getMessage());
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }
        }
    }

}
